#include <lib/holyhttp.h>
#include <utils/string.h>
#include <utils/address.h>
#include <utils/dbapi.h>
#include "cgi.h"
#include "blog.h"
#include "comment.h"
#include "guest.h"

static db_table_t blogs = {0};
static db_col_t blog_cols[BLOG_COL_NUM] = {
    DB_COL_SET_STR_UNQ(BLOG_COL_TITLE, "title", BLOG_TITLE_LEN),
    DB_COL_SET_STR(BLOG_COL_CONTENT, "content", BLOG_CONTENT_LEN),
    DB_COL_SET_STR(BLOG_COL_CREATED_TIME, BLOG_COLNAME_CREATED_TIME, TIME_STR_LEN),
    DB_COL_SET_STR(BLOG_COL_LAST_MODIFIED, BLOG_COLNAME_LAST_MODIFIED, TIME_STR_LEN),
    DB_COL_SET_INT(BLOG_COL_ACTIVE, "active"),
};

void cgi_index(holyreq_t *req)
{
    char args[ARGS_BUF_SIZE] = {0};
    int i = 0;
    db_result_t result;
    db_row_t *blog = NULL;
    char *order_by = "`"BLOG_COLNAME_LAST_MODIFIED"` DESC, `"BLOG_COLNAME_CREATED_TIME"` DESC";

    if (!blogs.select(&blogs, "active = 1", order_by, 0, 0, &result)) {
        goto exit;
    }

    STR_APPEND(args, sizeof(args), "online=%d\x01", is_online(req));
    db_foreach_result(blog, &result) {
        STR_APPEND(args, sizeof(args), "blogs.%d.id=%lld\x01", i, blog->id);
        STR_APPEND(args, sizeof(args), "blogs.%d.title=%s\x01",
            i, blog->values[BLOG_COL_TITLE].s);
        STR_APPEND(args, sizeof(args), "blogs.%d.content=%s\x01",
            i, blog->values[BLOG_COL_CONTENT].s);
        STR_APPEND(args, sizeof(args), "blogs.%d.created_time=%s\x01",
            i, blog->values[BLOG_COL_CREATED_TIME].s);
        STR_APPEND(args, sizeof(args), "blogs.%d.last_modified=%s\x01",
            i, blog->values[BLOG_COL_LAST_MODIFIED].s);
        ++i;
    }
    result.free(&result);

exit:
    req->render_separator = "\x01";
    req->send_frender_by(req, "index.html", args);
}

void cgi_show_blog(holyreq_t *req)
{
    char args[ARGS_BUF_SIZE] = {0}, guest_name[GUEST_NAME_LEN+1] = {0};
    char *id = req->get_arg(req, "id");
    db_row_t *row = NULL;
    char *content = NULL;
    db_result_t result = {0};
    int i = 0;

    if (!id) {
        req->send_status(req, BAD_REQUEST);
        return;
    }

    row = blogs.get(&blogs, atoi(id));
    if (!row) {
        req->send_status(req, NOT_FOUND);
        return;
    }

    content = base64dec(row->values[BLOG_COL_CONTENT].s);
    if (!content) {
        req->send_status(req, INTERNAL_ERROR);
        free(row);
        return;
    }

    /* blog data */
    STR_APPEND(args, sizeof(args), "online=%d\x01", is_online(req));
    STR_APPEND(args, sizeof(args), "blog.id=%lld\x01", row->id);
    STR_APPEND(args, sizeof(args), "blog.title=%s\x01",
        row->values[BLOG_COL_TITLE].s);
    STR_APPEND(args, sizeof(args), "blog.content=%s\x01",
        content);
    STR_APPEND(args, sizeof(args), "blog.created_time=%s\x01",
        row->values[BLOG_COL_CREATED_TIME].s);
    STR_APPEND(args, sizeof(args), "blog.last_modified=%s\x01",
        row->values[BLOG_COL_LAST_MODIFIED].s);
    
    free(row);
    free(content);

    /* comments */
    STR_APPEND(args, sizeof(args), "online=%d\x01", is_online(req));
    if (!get_comments(atoi(id), &result)) {
        goto exit;
    }

    db_foreach_result(row, &result) {
        content = base64dec(row->values[CMT_COL_CONTENT].s);
        if (!content) {
            continue;
        }
        get_guest_name(row->values[CMT_COL_GUEST].i, guest_name, sizeof(guest_name));
        STR_APPEND(args, sizeof(args), "comments.%d.id=%lld\x01", i, row->id);
        STR_APPEND(args, sizeof(args), "comments.%d.guest=%s\x01",
            i, guest_name[0] ? guest_name : mask_ip_str(row->values[CMT_COL_IP].s));
        STR_APPEND(args, sizeof(args), "comments.%d.content=%s\x01",
            i, content);
        STR_APPEND(args, sizeof(args), "comments.%d.created_time=%s\x01",
            i, row->values[CMT_COL_CREATED_TIME].s);
        free(content);
        ++i;
    }
    result.free(&result);

exit:
    req->render_separator = "\x01";
    req->send_frender_by(req, "blog.html", args);
}

void cgi_modify_blog(holyreq_t *req)
{
    char args[ARGS_BUF_SIZE] = {0};
    char location[MAX_URI_LEN] = {0};
    char *id = req->get_arg(req, "id");
    db_row_t *blog;
    char *content = NULL;

    if (!id) {
        req->send_status(req, BAD_REQUEST);
        return;
    }

    blog = blogs.get(&blogs, atoi(id));
    if (!blog) {
        req->send_status(req, NOT_FOUND);
        return;
    }

    if (req->method != POST_METHOD) {
        content = base64dec(blog->values[BLOG_COL_CONTENT].s);
        if (!content) {
            req->send_status(req, INTERNAL_ERROR);
        } else {
            STR_APPEND(args, sizeof(args), "modify=1\x01");
            STR_APPEND(args, sizeof(args), "title=[编辑文章] %s - %s\x01",
                blog->values[BLOG_COL_TITLE].s, g_site_name);
            STR_APPEND(args, sizeof(args), "blog.id=%lld\x01", blog->id);
            STR_APPEND(args, sizeof(args), "blog.title=%s\x01",
                blog->values[BLOG_COL_TITLE].s);
            STR_APPEND(args, sizeof(args), "blog.content=%s\x01",
                content);
            STR_APPEND(args, sizeof(args), "blog.created_time=%s\x01",
                blog->values[BLOG_COL_CREATED_TIME].s);
            STR_APPEND(args, sizeof(args), "blog.last_modified=%s\x01",
                blog->values[BLOG_COL_LAST_MODIFIED].s);
            
            req->render_separator = "\x01";
            req->send_frender_by(req, "edit.html", args);
            free(content);
        }

        free(blog);
        return;
    }

    // POST
    
    blog->values[BLOG_COL_TITLE].s = req->get_arg(req, "title");
    content = req->get_arg(req, "content");
    blog->values[BLOG_COL_LAST_MODIFIED].s = get_datetime_str();
    if (!blog->values[BLOG_COL_TITLE].s || !content) {
        req->send_status(req, BAD_REQUEST);
        return;
    }

    blog->values[BLOG_COL_CONTENT].s = base64enc(content);
    if (!blog->values[BLOG_COL_CONTENT].s) {
        req->send_status(req, INTERNAL_ERROR);
        return;
    }

    if (!blogs.set(&blogs, blog->id, blog->values)) {
        req->send_status(req, INTERNAL_ERROR);
    } else {
        snprintf(location, sizeof location, "/blog?id=%lld", blog->id);
        req->redirect(req, location);
    }
    
    free(blog->values[BLOG_COL_CONTENT].s);
    free(blog);
}

void cgi_add_blog(holyreq_t *req)
{
    char args[ARGS_BUF_SIZE] = {0};
    db_value_t values[BLOG_COL_NUM] = {0};
    char location[MAX_URI_LEN] = {0};
    char *content = NULL;
    int id;

    if (req->method != POST_METHOD) {
        STR_APPEND(args, sizeof(args), "modify=0,");
        STR_APPEND(args, sizeof(args), "title=[写文章] %s,", g_site_name);
        STR_APPEND(args, sizeof(args), "blog.title=,blog.content=,");
        req->send_frender_by(req, "edit.html", args);
        return;
    }
    
    values[BLOG_COL_TITLE].s = req->get_arg(req, "title");
    content = req->get_arg(req, "content");
    values[BLOG_COL_CREATED_TIME].s = get_datetime_str();
    values[BLOG_COL_LAST_MODIFIED].s = get_datetime_str();
    values[BLOG_COL_ACTIVE].i = 1;
    if (!values[BLOG_COL_TITLE].s || !content) {
        req->send_status(req, BAD_REQUEST);
        return;
    }

    values[BLOG_COL_CONTENT].s = base64enc(content);
    if (!values[BLOG_COL_CONTENT].s) {
        req->send_status(req, INTERNAL_ERROR);
        return;
    }

    id = blogs.add(&blogs, values);
    if (!id) {
        req->send_status(req, INTERNAL_ERROR);
    } else {
        snprintf(location, sizeof location, "/blog?id=%d", id);
        req->redirect(req, location);
    }

    free(values[BLOG_COL_CONTENT].s);
}

void cgi_del_blog(holyreq_t *req)
{
    char *id = req->get_arg(req, "id");
    int result = 0;

    if (!id) {
        req->send_status(req, BAD_REQUEST);
        return;
    }

#if 1
    db_row_t *blog = blogs.get(&blogs, atoi(id));
    if (!blog) {
        req->send_status(req, NOT_FOUND);
        return;
    }

    blog->values[BLOG_COL_ACTIVE].i = 0;
    if (blogs.set(&blogs, blog->id, blog->values)) {
        result = 1;
    }
    free(blog);
#else
    if (blogs.del(&blogs, atoi(id))) {
        result = 1;
    }
#endif

    if (result) {
        req->redirect(req, "/");
    } else {
        req->send_status(req, INTERNAL_ERROR);
    }
}

void init_blog(void)
{
    db_table_init(DEF_SQLITE3_DB, &blogs, "blog", blog_cols, ARRAY_SIZE(blog_cols));
}

